package work.linruchang.util;

import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.crypto.KeyUtil;
import cn.hutool.crypto.SecureUtil;
import cn.hutool.crypto.symmetric.AES;
import cn.hutool.crypto.symmetric.SymmetricAlgorithm;

import javax.crypto.SecretKey;
import java.util.stream.IntStream;

/**
 * 增强的安全相关工具类
 * @author LinRuChang
 * @version 1.0
 * @date 2022/11/13
 * @since 1.8
 **/
public class EnhanceSecureUtil extends SecureUtil {

    public static byte[] recognizableByteArray = new String("qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM123456789[]{};':,./<>?!@#$%^&*()_+").getBytes();

    public static Integer AES_BYTE_SIZE_16 = 16;
    public static Integer AES_BYTE_SIZE_24 = 24;
    public static Integer AES_BYTE_SIZE_32 = 32;

    /**
     * 生成AES密钥
     */
    public static String generateAESKeyStr() {
        return new String(generateAESKey(AES_BYTE_SIZE_32).getEncoded());
    }

    /**
     * 生成AES密钥
     * @return  获取密钥 {@link java.security.Key#getEncoded()}
     */
    public static SecretKey generateAESKey() {
        return generateAESKey(AES_BYTE_SIZE_32);
    }

    /**
     * 生成AES密钥
     * @param byteSize 密钥字节长度{@link EnhanceSecureUtil#AES_BYTE_SIZE_16}
     * @return 获取密钥 {@link java.security.Key#getEncoded()}
     */
    public static SecretKey generateAESKey(int byteSize) {
        Assert.isTrue(ArrayUtil.contains(new Integer[]{16,24,32},byteSize), "密钥字节数组的长度必须是16、24或32字节长度, 请检查");
        byte[] key = new byte[byteSize];
        IntStream.range(0,byteSize)
                .forEach(keyIndex -> {
                    int recognizableByteArrayIndex = RandomUtil.randomInt(0, recognizableByteArray.length);
                    key[keyIndex] = recognizableByteArray[recognizableByteArrayIndex];
                });
        return generateAESKey(key);
    }

    /**
     *
     * AES密钥长度必须是：16、24、32字节数组
     * @param key 密钥
     * @return 获取密钥 {@link java.security.Key#getEncoded()}
     */
    public static SecretKey generateAESKey(byte[] key) {
        Assert.isTrue(ArrayUtil.contains(new Integer[]{16,24,32},ArrayUtil.length(key)), "密钥字节数组的长度必须是16、24或32字节长度, 请检查");
        return KeyUtil.generateKey(SymmetricAlgorithm.AES.getValue(), key);
    }

    /**
     * 构造，使用默认的AES/ECB/PKCS5Padding
     * @param key 密钥
     * @return
     */
    public static AES aes(String key) {
        byte[] keyBytes = key.getBytes();
        Assert.isTrue(ArrayUtil.contains(new Integer[]{16,24,32},ArrayUtil.length(keyBytes)), "密钥字节数组的长度必须是16、24或32字节长度, 请检查");
        return new AES(keyBytes);
    }

}
